﻿using LeafCore.Commons.Utils;
using Microsoft.Extensions.Logging;
using RabbitMQ.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LeafCore.Components.RabbitMQ
{
    public class RabbitMQClient
    {
        private readonly ILogger<RabbitMQClient> _logger;
        private readonly RabbitMQOptions _options;

        public RabbitMQClient(ILogger<RabbitMQClient> logger, RabbitMQOptions options)
        {
            _logger = logger;
            _options = options;
        }

        /// <summary>
        ///  推送消息（简单模式）
        /// </summary>
        /// <param name="queueName">队列名称</param>
        /// <param name="message">消息内容</param>
        public void SimpleSendMessage(string queueName, string message)
        {
            using var connection = RabbitMQContext.GetConnection(_options.Host, _options.Port, _options.UserName, _options.Password);
            using var channel = connection.CreateModel();

            //创建队列
            channel.QueueDeclare(queueName, durable: true, exclusive: false, autoDelete: false, arguments: null);

            //消息持久化
            var properties = channel.CreateBasicProperties();
            properties.Persistent = true;

            //发送消息
            var body = message.ToUTF8Bytes();
            channel.BasicPublish(exchange: string.Empty, routingKey: queueName, mandatory: false, basicProperties: properties, body);
        }

        /****
         * 1、Direct Exchange – 处理路由键。需要将一个队列绑定
         * 到交换机上，要求该消息与一个特定的路由键完全匹配。这是一个完整的匹配。如果一个队列绑定到该交换机上要求路由键 “dog”，则只有被标记为“dog”的消息才被转发，不会转发dog.puppy，也不会转发dog.guard，只会转发dog
         * 2、Fanout Exchange – 不处理路由键。你只需要简单的将队列绑定到交换机上。一个发送到交换机的消息都会被转发到与该交换机绑定的所有队列上。很像子网广播，每台子网内的主机都获得了一份复制的消息。Fanout交换机转发消息是最快的。
         * 3、Topic Exchange – 将路由键和某模式进行匹配。此时队列需要绑定要一个模式上。符号“#”匹配一个或多个词，符号“*”匹配不多不少一个词。因此“audit.#”能够匹配到“audit.irs.corporate”，但是“audit.*”只会匹配到“audit.irs”。
        ****/

        /// <summary>
        ///  发布消息（Fanout Exchange）
        /// </summary>
        /// <param name="queueName">队列名称</param>
        /// <param name="message">消息内容</param>
        public void FanoutSendMessage(string queueName, string message)
        {
            using var connection = RabbitMQContext.GetConnection(_options.Host, _options.Port, _options.UserName, _options.Password);
            using var channel = connection.CreateModel();

            //创建交换机,fanout类型
            var exchangeName = $"{queueName}_fanout_exchange";
            channel.ExchangeDeclare(exchangeName, ExchangeType.Fanout);
            //创建队列
            channel.QueueDeclare(queueName, durable: true, exclusive: false, autoDelete: false);
            //把创建的队列绑定交换机,routingKey不用给值，给了也没意义的
            channel.QueueBind(queueName, exchangeName, routingKey: string.Empty);

            //消息持久化
            var properties = channel.CreateBasicProperties();
            properties.Persistent = true;

            var body = message.ToUTF8Bytes();//发送消息
            channel.BasicPublish(exchangeName, routingKey: string.Empty, properties, body);
        }


        /// <summary>
        ///  发布消息（Fanout Exchange）
        /// </summary>
        /// <param name="exchangeName">交换机名称</param>
        /// <param name="queueName">队列名称</param>
        /// <param name="message">消息内容</param>
        public void FanoutSendMessage(string exchangeName, string queueName, string message)
        {
            using var connection = RabbitMQContext.GetConnection(_options.Host, _options.Port, _options.UserName, _options.Password);
            using var channel = connection.CreateModel();

            //创建交换机,fanout类型
            channel.ExchangeDeclare(exchangeName, ExchangeType.Fanout);
            //创建队列
            channel.QueueDeclare(queueName, durable: true, exclusive: false, autoDelete: false);
            //把创建的队列绑定交换机,routingKey不用给值，给了也没意义的
            channel.QueueBind(queueName, exchangeName, routingKey: string.Empty);

            //消息持久化
            var properties = channel.CreateBasicProperties();
            properties.Persistent = true;

            //发送消息
            var body = message.ToUTF8Bytes();
            channel.BasicPublish(exchangeName, routingKey: string.Empty, properties, body);
        }

        /// <summary>
        ///  发布消息（Direct Exchange）
        /// </summary>
        /// <param name="queueName">队列名称</param>
        /// <param name="message">消息内容</param>
        public void DirectSendMessage(string queueName, string message)
        {
            using var connection = RabbitMQContext.GetConnection(_options.Host, _options.Port, _options.UserName, _options.Password);
            using var channel = connection.CreateModel();

            //创建交换机,Direct类型
            var exchangeName = $"{queueName}_direct_exchange";
            channel.ExchangeDeclare(exchangeName, ExchangeType.Direct);

            //创建队列
            channel.QueueDeclare(queueName, durable: true, exclusive: false, autoDelete: false);

            var routingKey = $"{queueName}";
            //队列绑定
            channel.QueueBind(queueName, exchangeName, routingKey);

            //消息持久化
            var properties = channel.CreateBasicProperties();
            properties.Persistent = true;

            //发送消息
            var body = message.ToUTF8Bytes();
            channel.BasicPublish(exchangeName, routingKey, properties, body);
        }

        /// <summary>
        ///  发布消息（Direct Exchange）
        /// </summary>
        /// <param name="exchangeName">交换机名称</param>
        /// <param name="queueName">队列名称</param>
        /// <param name="routingKey">路由键</param>
        /// <param name="message">消息内容</param>
        public void DirectSendMessage(string exchangeName, string queueName, string routingKey, string message)
        {
            using var connection = RabbitMQContext.GetConnection(_options.Host, _options.Port, _options.UserName, _options.Password);
            using var channel = connection.CreateModel();

            //创建交换机,Direct类型
            channel.ExchangeDeclare(exchangeName, ExchangeType.Direct);
            //创建队列
            channel.QueueDeclare(queueName, durable: true, exclusive: false, autoDelete: false);
            //队列绑定
            channel.QueueBind(queueName, exchangeName, routingKey);

            //消息持久化
            var properties = channel.CreateBasicProperties();
            properties.Persistent = true;

            //发送消息
            var body = message.ToUTF8Bytes();
            channel.BasicPublish(exchangeName, routingKey, properties, body);
        }

        /// <summary>
        ///  发布消息（Topic Exchange）
        /// </summary>
        /// <param name="queueName">队列名称</param>
        /// <param name="routingKey">路由键</param>
        /// <param name="message">消息内容</param>
        /// <param name="bindingKeys">绑定规则</param>
        public void TopicSendMessage(string queueName, string routingKey, string message, IEnumerable<string>? bindingKeys = null)
        {
            using var connection = RabbitMQContext.GetConnection(_options.Host, _options.Port, _options.UserName, _options.Password);
            using var channel = connection.CreateModel();

            //创建交换机,Topic类型
            var exchangeName = $"{queueName}_topic_exchange";
            channel.ExchangeDeclare(exchangeName, ExchangeType.Topic);
            //创建队列
            channel.QueueDeclare(queueName, durable: true, exclusive: false, autoDelete: false);
            //队列绑定
            if (!bindingKeys.IsNullOrEmpty())
            {
                foreach (string bindingKey in bindingKeys)
                {
                    channel.QueueBind(queueName, exchangeName, bindingKey);
                }
            }

            //消息持久化
            var properties = channel.CreateBasicProperties();
            properties.Persistent = true;

            //发送消息
            var body = message.ToUTF8Bytes();
            channel.BasicPublish(exchangeName, routingKey, properties, body);
        }

        /// <summary>
        /// 发布消息（Topic Exchange）
        /// </summary>
        /// <param name="exchangeName">交换机名称</param>
        /// <param name="queueName">队列名称</param>
        /// <param name="routingKey">路由键</param>
        /// <param name="message">消息内容</param>
        /// <param name="bindingKeys">绑定规则</param>
        public void TopicSendMessage(string exchangeName, string queueName, string routingKey, string message, IEnumerable<string>? bindingKeys = null)
        {
            using var connection = RabbitMQContext.GetConnection(_options.Host, _options.Port, _options.UserName, _options.Password);
            using var channel = connection.CreateModel();

            //创建交换机,Topic类型
            channel.ExchangeDeclare(exchangeName, ExchangeType.Topic);
            //创建队列
            channel.QueueDeclare(queueName, durable: true, exclusive: false, autoDelete: false);
            //队列绑定
            if (!bindingKeys.IsNullOrEmpty())
            {
                foreach (string bindingKey in bindingKeys)
                {
                    channel.QueueBind(queueName, exchangeName, bindingKey);
                }
            }

            //消息持久化
            var properties = channel.CreateBasicProperties();
            properties.Persistent = true;

            //发送消息
            var body = message.ToUTF8Bytes();
            channel.BasicPublish(exchangeName, routingKey, properties, body);
        }
    }
}
